package com.zhanghp.class030;

/**
 * 不用任何判断语句和比较操作，返回两个数的最大值
 * 测试链接 : https://www.nowcoder.com/practice/d2707eaf98124f1e8f1d9c18ad487f76
 *
 * @author zhanghp
 * @since 2024/4/3 18:09
 */
public class Code02_GetMaxWithoutJudge {

    public static void main(String[] args) {
        Solution solution = new Solution();
        int a = Integer.MIN_VALUE;
        int b = Integer.MAX_VALUE;
        // getMax1方法会错误，因为溢出
        System.out.println(solution.getMax(a, b));
        // getMax2方法永远正确
        System.out.println(solution.getMax2(a, b));
    }
    static class Solution {
        /**
         * 有溢出风险的实现
         *
         * @param a int整型
         * @param b int整型
         * @return int整型
         */
        public int getMax(int a, int b) {
            // write code here
            int c = a - b;
            // c非负，returnA -> 1
            // c非负，returnB -> 0
            // c负数，returnA -> 0
            // c负数，returnB -> 1
            int returnA = sign(c);
            int returnB = flip(returnA);
            return returnA * a + returnB * b;
        }

        /**
         *没有任何问题的实现
         * <p>
         * 1. a,b同符号位不会出现溢出风险，这时的符号位源头，看a-b后的结果的符号位（和getMax一样的思路）
         * <p>
         * 2. a,b不同符号位，则会出现溢出风险，这时，采取看a，b的符号位
         * <p>
         * ps: diffAb 只是用来区别a,b是否相同，相同的前提，来判断c的符号位，而不同的前提，判断a，b符号位（当时困扰半天，终于得出了这个结论）
         *
         * @param a
         * @param b
         * @return
         */
        public int getMax2(int a, int b) {
            int c = a - b;

            // 符号位
            int signA = sign(a);
            int signB = sign(b);
            int signC = sign(c);

            // 看是否符号相同，相同为0，不同为1
            int diffAb = signA ^ signB;
            int samAb = flip(diffAb);
            int returnA = diffAb * signA + samAb * signC;
            int returnB = flip(returnA);
            return returnA * a+ returnB * b;
        }

        // 必须保证n一定是0或者1
        // 0变1，1变0
        public int flip(int n) {
            return n ^ 1;
        }

        /**
         * 获取符号位，并反转符号
         *
         * @param n 数
         * @return 负数-0 正数-0
         */
        public int sign(int n){
            return flip(n >>> 31);
        }
    }
}
